package qc.module.platform.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QCConstant;
import qc.common.core.enums.ResourceStatusFlagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.tree.QCTreeNode;
import qc.common.core.tree.TreeDataDto;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.module.platform.dto.api.APIDto;
import qc.module.platform.dto.api.APIQueryConditionDto;
import qc.module.platform.dto.menu.*;
import qc.module.platform.entity.QcMenus;
import qc.module.platform.mapper.MenusMapper;
import qc.module.platform.repository.QcMenusRepository;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * MenusService
 *
 * @author QuCheng Tech
 * @create 2023/02/07
 */
@Service
public class MenusService {
    private QcMenusRepository repository;
    private ProjectService projectService;
    private RoleMenuService roleMenuService;

    @Autowired
    public void setQcMenusRepository(QcMenusRepository repository) {
        this.repository = repository;
    }

    @Autowired
    public void setProjectService(ProjectService projectService) {
        this.projectService = projectService;
    }

    @Autowired
    public void setRoleMenuService(RoleMenuService roleMenuService) {
        this.roleMenuService = roleMenuService;
    }
    
    @Autowired
    private ApiService apiService;
    
    @Autowired
    private MenuApiService menuApiService;

    /**
     * 列表方式返回菜单简要信息，根据条件查询
     *
     * @param condition 查询条件DTO
     * @return 返回简要菜单信息列表
     * @throws QCPromptException
     * @author QuCheng Tech
     * @since 2023/7/3
     */
    public List<MenuSimpleDto> queryListSimple(MenuQueryConditionDto condition) throws QCPromptException {
        List<MenuDto> menuDtos = queryListDetail(condition);
        return MenusMapper.MAPPER.toSimpleDtoList(menuDtos);
    }

    /**
     * 树形结构方式返回菜单简要信息，根据条件查询
     *
     * @param condition 查询条件DTO
     * @return 返回树形结构的简要菜单信息
     * @author QuCheng Tech
     * @since 2023/7/4
     */
    public List<MenuTreeSimpleDto> queryTreeSimple(MenuQueryConditionDto condition) throws QCPromptException {
        List<MenuTreeDto> menuTreeDtos = queryTreeDetail(condition);
        return MenusMapper.MAPPER.toTreeSimpleDtoList(menuTreeDtos);
    }

    /**
     * 列表方式返回菜单详情，根据条件查询
     *
     * @param condition 查询条件DTO
     * @return 返回详细菜单信息列表
     * @throws QCPromptException
     * @author QuCheng Tech
     * @since 2023/7/3
     */
    public List<MenuDto> queryListDetail(MenuQueryConditionDto condition) throws QCPromptException {
        if (condition == null)
            throw new QCPromptException("查询信息不能为空");

        List<QcMenus> ens = queryProjectMenus(condition.getProject(), condition.getKeywords());

        if (ens.size() > 0x0 && ens != null) {
            //entityList转为dtoList
            List<MenuDto> dtos = MenusMapper.MAPPER.toDtoList(ens);

            List<MenuDto> setLevelDtos = new ArrayList<>();

            //获取根目录菜单集合，设置各层层级(层级从1开始)
            List<MenuDto> rootMenus = getSubMenus(dtos, 0x0);
            for (MenuDto rootDto : rootMenus) {
                rootDto.setLevel(0x1);
                setLevelDtos.add(rootDto);
                //设置子菜单层级
                getSubListMenus(setLevelDtos, dtos, rootDto, rootDto.getLevel() + 1);
            }

            return setLevelDtos;
        }

        return null;
    }

    /**
     * 树形结构方式返回菜单详情，根据条件查询
     *
     * @param condition 查询条件DTO
     * @return 返回树形结构的详细菜单信息
     * @author QuCheng Tech
     * @since 2023/7/4
     */
    public List<MenuTreeDto> queryTreeDetail(MenuQueryConditionDto condition) throws QCPromptException {
        if (condition == null)
            throw new QCPromptException("查询信息不能为空");

        List<QcMenus> ens = queryProjectMenus(condition.getProject(), condition.getKeywords());

        if (ens.size() > 0x0 && ens != null) {
            //entityList转为dtoList
            List<MenuDto> dtos = MenusMapper.MAPPER.toDtoList(ens);

            List<MenuTreeDto> result = new ArrayList<>();

            //获取根目录菜单集合，设置各层层级(层级从1开始)
            List<MenuDto> rootMenus = getSubMenus(dtos, 0x0);
            for (MenuDto rootDto : rootMenus) {
                rootDto.setLevel(0x1);
                MenuTreeDto treeDto = new MenuTreeDto();
                List<MenuTreeDto> childs = new ArrayList<>();
                treeDto.setInfo(rootDto);
                treeDto.setChilds(childs);
                getSubTreeMenus(dtos, rootDto, childs, rootDto.getLevel() + 1);
                result.add(treeDto);
            }

            return result;
        }
        return null;
    }

    /***
     * 查询菜单，以TreeTable形式返回结果
     *
     * @param condition 查询条件
     * @return java.util.List<qc.module.platform.dto.menu.MenuTreeDto>
     * @author QuCheng Tech
     * @since 2023/9/1
     */
    public List<MenuTreeTableDetailDto> queryTreeTableDetail(MenuQueryConditionDto condition) throws QCPromptException {
        if (condition == null)
            throw new QCPromptException("查询信息不能为空");

        List<QcMenus> ens = queryProjectMenus(condition.getProject(), condition.getKeywords());

        if (ens.size() > 0x0 && ens != null) {
            //entityList转为dtoList
            List<MenuTreeTableDetailDto> dtos = MenusMapper.MAPPER.toTreeTableDetailDtoList(ens);

            List<MenuTreeTableDetailDto> result = new ArrayList<>();
            //设定返回的菜单层级为3
            int returnTreeLevel = 0x3;
            //由于查询条件中有关键字，可能查询的结果中没有一级菜单，如果没有一级菜单时需要根据查询结果进行处理
            // 获取一级
            List<MenuTreeTableDetailDto> rootMenus = dtos.stream().filter(p -> p.getParentid() == 0x0).collect(Collectors.toList());
            if (rootMenus != null && rootMenus.size() > 0x0) {
                //遍历一级，添加到返回集合中，获取二级
                for (MenuTreeTableDetailDto level1MenuDto : rootMenus) {
                    //判断返回树形结构需要需要获取第2级
                    if (returnTreeLevel >= 0x2) {
                        List<MenuTreeTableDetailDto> level2Menus = dtos.stream().filter(p -> level1MenuDto.getId() == (p.getParentid())).collect(Collectors.toList());
                        if (level2Menus != null && level2Menus.size() > 0x0) {
                            //遍历二级，添加到返回集合中，获取三级
                            for (MenuTreeTableDetailDto level2MenuDto : level2Menus) {
                                //判断返回树形结构需要需要获取第3级
                                if (returnTreeLevel >= 0x3) {
                                    List<MenuTreeTableDetailDto> level3Menus = dtos.stream().filter(p -> level2MenuDto.getId() == (p.getParentid())).collect(Collectors.toList());
                                    if (level3Menus != null && level3Menus.size() > 0x0) {
                                        //遍历三级，添加到返回集合中，获取四级
                                        for (MenuTreeTableDetailDto level3MenuDto : level3Menus) {
                                            //大于4级的暂时不进行获取，后继可进行添加
                                        }
                                        level2MenuDto.setChildren(level3Menus);
                                    }
                                }
                            }
                            level1MenuDto.setChildren(level2Menus);
                        }
                    }

                    result.add(level1MenuDto);
                }
            } else {
                //查询的结果中没有一级菜单，逐个遍历查询结果进行处理
                for (MenuTreeTableDetailDto menuDto : dtos) {
                    //如果查询结果中有该菜单的父级，当前菜单不处理，在该菜单的父级中进行处理
                    List<MenuTreeTableDetailDto> parentMenus = dtos.stream().filter(p -> p.getId() == menuDto.getParentid()).collect(Collectors.toList());
                    if (parentMenus != null && parentMenus.size() > 0x0)
                        continue;

                    //查询结果中没有该菜单的父级，处理该菜单，获取该菜单的子级
                    List<MenuTreeTableDetailDto> childMenus = dtos.stream().filter(p -> p.getParentid() == menuDto.getId()).collect(Collectors.toList());
                    if (childMenus != null && childMenus.size() > 0x0) {
                        menuDto.setChildren(childMenus);
                    }

                    result.add(menuDto);
                }
            }

            return result;
        }

        return null;
    }

    /***
     * 获取指定项目中的所有菜单信息
     *
     * @param projectCode 项目编码
     * @return java.util.List<qc.module.platform.entity.QcMenus>
     * @author QuCheng Tech
     * @since 2023/9/1
     */
    public List<QcMenus> getProjectAllMenus(String projectCode) throws QCPromptException {
        return queryProjectMenus(projectCode, null);
    }

    /**
     * 获取指定项目编码的菜单集合，不管菜单的状态是否有效
     *
     * @param projectCode 项目编码
     * @param keywords    关键字，可以匹配name（标题）、path（路由）、content（内容或文件路径）中的任意一个
     * @return 菜单集合
     * @throws QCPromptException
     * @author QuCheng Tech
     * @since 2023/7/4
     */
    public List<QcMenus> queryProjectMenus(String projectCode, String keywords) throws QCPromptException {
        //1.判空
        if (StringUtils.isBlank(projectCode))
            throw new QCPromptException("项目编码不能为空");

        //2.判断项目编码是否存在，不存在则提示
        if (!projectService.hasCodeExist(projectCode))
            throw new QCPromptException("项目不存在");

        LambdaQueryWrapper<QcMenus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcMenus::getProjectcode, projectCode);
        if (!StringUtils.isBlank(keywords)) {
            wrapper.and(p -> {
                p.like(QcMenus::getName, keywords).or().like(QcMenus::getPath, keywords).or().like(QcMenus::getContent, keywords);
            });
        }

        wrapper.orderByAsc(QcMenus::getOdr);
        wrapper.orderByAsc(QcMenus::getId);

        return repository.selectList(wrapper);
    }

    /**
     * 获取根据关键字过滤的菜单的所有上级菜单，并添加到返回菜单集合中
     *
     * @param menuList         过滤前的菜单集合
     * @param menu             根据关键字过滤的菜单信息
     * @param filterResultList 过滤后返回的菜单集合
     * @author QuCheng Tech
     * @since 2023/7/4
     */
    public void getSupperMenus(List<MenuDto> menuList, MenuDto menu, List<MenuDto> filterResultList) {
        //从所有数据集中找出父级节点
        List<MenuDto> parentList = menuList.stream()
                .filter(parentMenu -> parentMenu.getId() == menu.getParentid())
                .collect(Collectors.toList());
        //如果有父节点，判断父节点是否是根节点，是则添加到结果集，不是则继续查找父节点的上级节点
        if (parentList.size() != 0x0 && parentList != null) {
            if (parentList.get(0).getParentid() != 0x0) {
                getSupperMenus(menuList, parentList.get(0), filterResultList);
            }
            filterResultList.add(parentList.get(0));
        }
    }

    /**
     * 获取某一层级的菜单集合
     *
     * @param dtos     所有菜单集合
     * @param parentId 父id
     * @return 返回菜单当前层级的菜单集合
     */
    private List<MenuDto> getSubMenus(List<MenuDto> dtos, Integer parentId) {
        return dtos.stream().filter(menuDto -> menuDto.getParentid() == parentId).collect(Collectors.toList());
    }

    /**
     * 设置当前层级
     *
     * @param setLevelDtos 层级设置后的结果集
     * @param dtos         所有菜单集合
     * @param parentMenu   当前层级的父级菜单
     * @param level        当前层级
     */
    private void getSubListMenus(List<MenuDto> setLevelDtos, List<MenuDto> dtos, MenuDto parentMenu, Integer level) {
        List<MenuDto> subMenus = getSubMenus(dtos, parentMenu.getId());
        for (MenuDto subMenu : subMenus) {
            subMenu.setLevel(level);
            setLevelDtos.add(subMenu);
            getSubListMenus(setLevelDtos, dtos, subMenu, level + 1);
        }
    }

    /**
     * 设置的当前层级，拼接父级菜单的子孙层级结构
     *
     * @param dtos          所有菜单集合
     * @param parentMenuDto 父级菜单
     * @param parentChilds  父级菜单的子孙集合
     * @param level         当前层级
     */
    public void getSubTreeMenus(List<MenuDto> dtos, MenuDto parentMenuDto, List<MenuTreeDto> parentChilds, Integer level) {
        List<MenuDto> subMenus = getSubMenus(dtos, parentMenuDto.getId());
        for (MenuDto subMenu : subMenus) {
            subMenu.setLevel(level);

            MenuTreeDto menuTreeDto = new MenuTreeDto();
            List<MenuTreeDto> childs = new ArrayList<>();
            menuTreeDto.setInfo(subMenu);
            menuTreeDto.setChilds(childs);

            parentChilds.add(menuTreeDto);

            getSubTreeMenus(dtos, subMenu, childs, level + 1);
        }
    }

    /**
     * 获取指定菜单详情
     *
     * @param id 菜单id
     * @return 菜单详情
     * @throws QCPromptException
     * @author QcCheng Tech
     * @since 2023/7/3
     */
    public MenuDto get(Integer id) throws QCPromptException {
        if (id == null || id.intValue() < 0x1)
            throw new QCPromptException("菜单id不能为空");

        QcMenus en = getEntity(id);
        if (en != null)
            return MenusMapper.MAPPER.toDto(en);

        return null;
    }

    /**
     * 获取指定id的菜单Entity
     *
     * @param id 菜单ID
     * @return qc.module.platform.entity.QcMenus
     * @author QuCheng Tech
     * @since 2023/9/27
     */
    QcMenus getEntity(Integer id) {
        return repository.selectById(id);
    }

    /**
     * 新增菜单信息
     *
     * @param dto 菜单信息
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/7/3
     */
    public String add(MenuDto dto) {
        //1.判空
        if (StringUtils.isBlank(dto.getPcode()))
            return QCUnifyReturnValue.Warn("项目编码不能为空");
        if (StringUtils.isBlank(dto.getTitle()))
            return QCUnifyReturnValue.Warn("菜单名称不能为空");

        //2.判断项目编码是否存在，不存在则提示
        if (!projectService.hasCodeExist(dto.getPcode()))
            return QCUnifyReturnValue.Warn("项目不存在");

        //3.判断菜单名称不重复
        //if (hasNameExist(dto.getTitle(), 0x0, dto.getPcode()))
        //    return QCUnifyReturnValue.Warn("菜单名称已存在，不能重复添加");

        //4.如果父id>0
        if (dto.getParentid() > 0x0) {
            //4.1 判断父id记录是否存在，不存在则提示
            if (!hasIdExist(dto.getParentid()))
                return QCUnifyReturnValue.Warn("指定上级菜单不存在");
        }

        //5.dto转为entity
        QcMenus en = MenusMapper.MAPPER.MenuDtoToEntity(dto);

        //6.设置id栏目,获取数据库中的最大id+1后赋值
        en.setId(generateId());

        //对菜单中的路由地址进行处理
        //1.验证是否以路由分隔符反斜线开始，如果不是自动添加
        //2.如果为子级菜单，前面需要带有父级的路由地址；判断依据：有至少2个反斜线；不能直接根据父级的路由地址进行匹配，有可能修改父级的路由地址后子级的路由地址没有修改
        if (!StringUtils.isBlank(en.getPath())) {
            if (!en.getPath().startsWith(QCConstant.ROUTE_SPLIT)) {
                en.setPath(QCConstant.ROUTE_SPLIT + en.getPath());
            }
            //判断当前菜单的路由地址是否已包含有父级路由地址；如果从序号1开始后还包含有路由地址分隔符
            if (en.getPath().indexOf(QCConstant.ROUTE_SPLIT, 0x1) < 0x0) {
                //判断是否有父级
                if (en.getParentid() != null && en.getParentid() > 0x0) {
                    //判断父级的路由是否为空，如果为空不需要以父级的路由开始
                    QcMenus parentMenu = getEntity(en.getParentid());
                    if (parentMenu != null) {
                        if (!StringUtils.isBlank(parentMenu.getPath())) {
                            en.setPath(parentMenu.getPath() + en.getPath());
                        }
                    }
                }
            }
        }

        //7.保存数据记录
        if (repository.insert(en) < 0x0)
            return QCUnifyReturnValue.Warn("保存失败");
        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改指定菜单信息
     *
     * @param dto 菜单信息
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/7/3
     */
    public String update(MenuDto dto) {
        //1.判空
        if (dto.getId() < 0x1)
            return QCUnifyReturnValue.Warn("菜单id不能为空");
        if (StringUtils.isBlank(dto.getTitle()))
            return QCUnifyReturnValue.Warn("菜单名称不能为空");

        //2.判断菜单是否存在，不存在则提示
        if (!hasIdExist(dto.getId()))
            return QCUnifyReturnValue.Warn("修改的菜单信息不存在");

        //3.判断菜单名称不重复
        //if (hasNameExist(dto.getTitle(), dto.getId(), dto.getPcode()))
        //    return QCUnifyReturnValue.Warn("菜单名称已存在，不能重复添加");

        //4.如果父id>0
        if (dto.getParentid() > 0x0) {
            //4.1 判断父id记录是否存在，不存在则提示
            if (!hasIdExist(dto.getParentid()))
                return QCUnifyReturnValue.Warn("指定上级菜单不存在");
        }

        //5.dto转为entity
        QcMenus en = MenusMapper.MAPPER.MenuDtoToEntity(dto);

        //对菜单中的路由地址进行处理
        //1.验证是否以路由分隔符反斜线开始，如果不是自动添加
        //2.如果为子级菜单，前面需要带有父级的路由地址；判断依据：有至少2个反斜线；不能直接根据父级的路由地址进行匹配，有可能修改父级的路由地址后子级的路由地址没有修改
        if (!StringUtils.isBlank(en.getPath())) {
            if (!en.getPath().startsWith(QCConstant.ROUTE_SPLIT)) {
                en.setPath(QCConstant.ROUTE_SPLIT + en.getPath());
            }
            //判断当前菜单的路由地址是否已包含有父级路由地址；如果从序号1开始后还包含有路由地址分隔符
            if (en.getPath().indexOf(QCConstant.ROUTE_SPLIT, 0x1) < 0x0) {
                //判断是否有父级
                if (en.getParentid() != null && en.getParentid() > 0x0) {
                    //判断父级的路由是否为空，如果为空不需要以父级的路由开始
                    QcMenus parentMenu = getEntity(en.getParentid());
                    if (parentMenu != null) {
                        if (!StringUtils.isBlank(parentMenu.getPath())) {
                            en.setPath(parentMenu.getPath() + en.getPath());
                        }
                    }
                }
            }
        }

        //6.修改数据记录
        repository.updateById(en);

        return QCUnifyReturnValue.Success();
    }

    /**
     * 删除指定菜单信息
     *
     * @param id            菜单信息
     * @param isLogicDelete 是否为逻辑删除
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/7/3
     */
    public String delete(Integer id, boolean isLogicDelete) {
        //1.判空
        if (id < 0x1)
            return QCUnifyReturnValue.Warn("删除的id不能为空");

        //2.要删除的菜单是否存在，不存在则提示
        if (!hasIdExist(id))
            return QCUnifyReturnValue.Warn("要删除的菜单不存在");

        //3.判断是否为逻辑删除
        if (isLogicDelete) {
            //3.1 逻辑删除，修改记录状态标记，不删除记录
            LambdaUpdateWrapper<QcMenus> wrapper = new LambdaUpdateWrapper<>();
            wrapper.set(QcMenus::getFlag, ResourceStatusFlagEnum.DELETED)
                    .eq(QcMenus::getId, id);
            repository.update(null, wrapper);
        } else {
            //3.2 物理删除
            //a.判断是否有子菜单，存在不允许删除
            if (getChildCount(id) > 0x0)
                return QCUnifyReturnValue.Warn("当前菜单下存在子菜单，不允许删除");

            //b.删除菜单与角色的关联关系
            roleMenuService.deleteByMenuId(id);

            //c.删除记录
            repository.deleteById(id);
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 查询指定菜单是否存在
     *
     * @param id 菜单id
     * @return 返回true表示存在，false表示不存在
     * @author QuCheng Tech
     * @since 2023/7/3
     */
    public boolean hasIdExist(Integer id) {
        LambdaQueryWrapper<QcMenus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcMenus::getId, id);

        QcMenus en = repository.selectOne(wrapper);
        if (en != null)
            return true;

        return false;
    }

    /**
     * 查询菜单名称是否重复
     *
     * @param name 名称
     * @param id   ID，新增时设置ID为0，修改时设置ID为记录ID
     * @return true表示名称已存在，false表示名称不存在
     * @author QuCheng Tech
     * @since 2023/5/28
     */
    //boolean hasNameExist(String name, Integer id,String projectCode) {
    //    LambdaQueryWrapper<QcMenus> wrapper = new LambdaQueryWrapper<>();
    //    wrapper.eq(QcMenus::getName, name)
    //            .eq(QcMenus::getProjectcode,projectCode)
    //            .ne(QcMenus::getId, id);
    //
    //    QcMenus en = repository.selectOne(wrapper);
    //    if (en != null)
    //        return true;
    //
    //    return false;
    //}

    /**
     * 获取指定菜单ID的子菜单数量，不管子菜单的状态
     *
     * @param id 菜单ID
     * @return 子菜单数量
     * @author QuCheng Tech
     * @since 2023/5/28
     */
    private Integer getChildCount(Integer id) {
        LambdaQueryWrapper<QcMenus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcMenus::getParentid, id);

        Long childCount = repository.selectCount(wrapper);
        if (childCount > 0x0) {
            return childCount.intValue();
        }
        return 0x0;
    }

    /**
     * 生成记录ID，获取数据库表中的最大记录ID+1
     *
     * @return 生成记录ID
     * @author QuCheng Tech
     * @since 2023/5/28
     */
    Integer generateId() {
        Integer maxRecordId = getMaxId();
        return maxRecordId + 1;
    }

    /**
     * 获取数据库表中的最大ID值，没有记录时返回0
     *
     * @return 返回数据库表中的最大ID值
     * @author QuCheng Tech
     * @since 2023/5/28
     */
    Integer getMaxId() {
        LambdaQueryWrapper<QcMenus> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(QcMenus::getId)
                .orderByDesc(QcMenus::getId);

        QcMenus en = repository.selectOne(wrapper);
        if (en != null)
            return en.getId();

        return 0x0;
    }

    /**
     * 获取菜单API关联关系
     *
     * @param menuId 菜单ID
     * @return List<MenuAPIDto>
     * @author QuCheng Tech
     * @since 2024/5/8
     */
    public List<MenuAPIDto> getMenuApis(Integer menuId){
        List<MenuAPIDto> result = new ArrayList<>();

        //1.获取所有api列表集合
        APIQueryConditionDto conditionDto = new APIQueryConditionDto();
        List<APIDto> apiDtoList = apiService.query(conditionDto);

        if (CollectionUtils.isNotEmpty(apiDtoList)) {
            //2.获取菜单关联api唯一标识集合
            List<String> apis = menuApiService.getApis(menuId);

            //3.处理返回结果集
            for (APIDto apiDto : apiDtoList) {
                boolean related = false;
                if (apis != null && apis.size() > 0x0) {
                    if (apis.contains(apiDto.getId())) {
                        related = true;
                    }
                }
                MenuAPIDto dto = new MenuAPIDto();
                dto.setApi(apiDto);
                dto.setChecked(related);
                result.add(dto);
            }
            
        }
        
        return result;
    }

    /**
     * 以树形结构返回结果，按Api接口分组分2级列出所有接口；
     *
     * @param menuId: 菜单id
     * @return TreeDataDto 返回结果集
     * @author QcCheng Tech
     * @date 2024/5/10
     */
    public TreeDataDto getMenuApisTree(Integer menuId) throws QCPromptException {
        if (menuId == null) throw new QCPromptException("菜单ID不能为空");
        //1.构建返回结果集
        TreeDataDto result = new TreeDataDto();
        List<QCTreeNode> treeNodes = new ArrayList<>();

        //2.获取菜单关联的api唯一标识集合
        List<String> menuApis = menuApiService.getApis(menuId);
        
        //3.设置结果集中菜单已关联的api唯一标识
        if (CollectionUtils.isNotEmpty(menuApis)) {
            List<String> checkedKeys = menuApis.stream().map(Object::toString).collect(Collectors.toList());
            result.setCheckedKeys(checkedKeys);
        }
        
        //4.查询所有API信息集合
        List<APIDto> allApis = apiService.query(new APIQueryConditionDto());

        //5.查询所有API分组集合
        List<String> groups = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(allApis)){
            //List<String> groupList = allApis.stream().map(map -> map.getApigroup()).collect(Collectors.toList());
            List<String> groupList = new ArrayList<>();
            for (APIDto apiDto : allApis){
                if (StringUtils.isNotBlank(apiDto.getApigroup())){
                    groupList.add(apiDto.getApigroup());
                }else {
                    groupList.add("未分组");
                    apiDto.setApigroup("未分组");
                }
            }
            groups = groupList.stream().distinct().collect(Collectors.toList());//去重
        }

        
        //6.将分组作为父级，子级为对应分组的api
        if (CollectionUtils.isNotEmpty(groups)){
            for (String group : groups){
                QCTreeNode level1TreeNode = new QCTreeNode();
                level1TreeNode.setKey(group);
                level1TreeNode.setTitle(group);
                level1TreeNode.setLeaf(true);
                
                //根据当前分组找出子节点api
                List<APIDto> subApis = allApis.stream().filter(p -> p.getApigroup().equals(group)).collect(Collectors.toList());
                if (!subApis.isEmpty()) {
                    level1TreeNode.setLeaf(false);

                    List<QCTreeNode> subTreeNodes = new ArrayList<>();
                    for (APIDto apiDto : subApis){
                        QCTreeNode subTreeNode = new QCTreeNode();
                        subTreeNode.setKey(apiDto.getId());
                        subTreeNode.setTitle(apiDto.getName());
                        subTreeNode.setLeaf(true);
                        subTreeNodes.add(subTreeNode);
                    }
                    ////结果按照key升序
                    level1TreeNode.setChildren(subTreeNodes.stream().sorted(Comparator.comparing(QCTreeNode::getKey)).collect(Collectors.toList()));
                }
                treeNodes.add(level1TreeNode);
            }
        }
        result.setNodes(treeNodes);
        
        return result;
    }

    /**
     * 设置菜单API关联关系
     *
     * @param dto
     * @return 成功返回null，失败返回错误或提示信息
     * @author QuCheng Tech
     * @since 2024/5/8
     */
    public String setMenuApis(MenuAPISetDto dto){
        if (dto == null)
            return QCUnifyReturnValue.Warn("传入的设置条件为空");

        int menuId = dto.getMenuid();
        QcMenus en = getEntity(menuId);
        if (en == null)
            return QCUnifyReturnValue.Warn("指定的菜单信息错误或不存在");

        //先按菜单ID删除已有的关联
        menuApiService.deleteByMenuId(menuId);

        //如果有设置关联API信息，逐个进行添加
        if (CollectionUtils.isNotEmpty(dto.getApis())){
            for (String api : dto.getApis()){
                //先判断api是否存在，不存在的不添加关联关系
                if (apiService.isExist(api)){
                    menuApiService.add(menuId,api);
                }
                
            }
        }

        return QCUnifyReturnValue.Success();
    }

}
